﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LucyGrid;
using System.IO;

namespace LucyDemo.Hotel
{
	class HotelLoader : AbstractDemo
	{
		Random Rnd = new Random();
		public override string Info()
		{
			return "Transforms hotel information from multiple soources into a JSON object";
		}

		public int NumberOfHotels = 4000;
		public int RoomsPerHotel = 10;
		public int AvailabilityDays = 365;



		public IEnumerable<string> YieldHotels()
		{
			for (var c = 0; c != NumberOfHotels; ++c)
			{
				yield return c + @",destination,0089678758,""Hotel description lorem ipsum,Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
Sed eget nulla eu turpis vestibulum sodales id a sapien. Fusce vitae convallis 
lacus. Aliquam aliquet est ut sem pellentesque, in gravida purus convallis. In magna turpis, ultrices convallis 
convallis sit amet, hendrerit a dolor. Suspendisse id turpis ac leo vehicula feugiat. Aliquam porta ligula eget hendrerit sollicitudin. 
Donec tempus purus eu nisl scelerisque, a blandit dolor accumsan. Integer congue, quam non porta varius, arcu ipsum porta 
lectus, ac pretium libero lectus ut nulla."", ""Address hotel street, 19""";
			}
		}

		string[] RoomTypes = new string[] { "Single", "Double", "Triple" };
		public IEnumerable<string> YieldHotelRooms()
		{
			for (var c = 0; c != NumberOfHotels; ++c)
				for (var r = 0; r != RoomsPerHotel; ++r)
					yield return string.Join(",", new string[]{
						c.ToString(),
						r.ToString(),
						RoomTypes[Rnd.Next(0, RoomTypes.Length)]
					});
		}

		public IEnumerable<string> YieldAvailability()
		{
			Func<string> dbl = () => string.Format("\"{0}\"", (100 * (1+Rnd.NextDouble())));
			for (var c = 0; c != NumberOfHotels; ++c)
				for (var r = 0; r != RoomsPerHotel; ++r)
					for (var d = 0; d != AvailabilityDays; ++d)
						yield return string.Join(",", new string[]{
						c.ToString(),
						r.ToString(),
						d.ToString(),
						"RoomOnly",
						dbl(),
						"Breakfast",
						dbl(),
						"HaslfBoard",
						dbl(),
						"FullBoard",
						dbl(),
						"AllInclusive",
						dbl()
					});
		}

		[Serializable]
		class HotelBaseData
		{
			public string HotelInfo;
			public List<string> Rooms;
			public List<string> Availability;
		}

		IEnumerable<string> CSVSplit(string text)
		{
			var parts = text.Split(',');
			var start = -1;
			for (var c = 0; c != parts.Length; ++c)
			{
				if (!parts[c].StartsWith("\"") && start == -1)
				{
					yield return parts[c].Trim();
					continue;
				}
				if (parts[c].EndsWith("\""))
				{
					var str = start == -1 ? parts[c].Trim() : string.Join(",", parts.Skip(start).Take(c - start + 1).ToArray())
						.Trim();
					yield return str.Substring(1, str.Length - 2); // Remove quotes
					start = -1;
					continue;
				}
				start = c;
			}
		}


		IEnumerable<HotelBaseData> YieldHotelBaseData()
		{
			foreach (string hotel in YieldHotels())
			{
				var res = new HotelBaseData()
				{
					HotelInfo = hotel,
					Rooms = new List<string>(),
					Availability = new List<string>()
				};
				var hid = hotel.Split(',')[0];
				foreach (var room in YieldHotelRooms())
				{
					if (room.Split(',')[0] == hid)
						res.Rooms.Add(room);
				}
				foreach (var availability in YieldAvailability())
				{
					if (availability.Split(',')[0] == hid)
						res.Availability.Add(availability);
				}
				yield return res;
			}
		}


		public override string Run(bool enableLocalProcessing)
		{
			var res = YieldHotelBaseData()
				.AsParallelGrid(h =>
				{
					var rooms = h.Rooms.Select(r =>
					{
						var parts = CSVSplit(r).ToArray();
						return new
						{
							HotelId = int.Parse(parts[0]),
							RoomId = int.Parse(parts[1]),
							Type = parts[2]
						};
					})
					.Join(h.Availability.Select(a =>
					{
						var parts = CSVSplit(a).ToArray();
						return new
						{
							HotelId = int.Parse(parts[0]),
							RoomId = int.Parse(parts[1]),
							Day = int.Parse(parts[2]),
							RoomOnly = double.Parse(parts[4]),
							Breakfast = double.Parse(parts[6]),
							HaslfBoard = double.Parse(parts[8]),
							FullBoard = double.Parse(parts[10]),
							AllInclusive = double.Parse(parts[12])
						};
					}), o => o.RoomId, i => i.RoomId, (o, i) => new { o, i })
					.GroupBy(j => j.o)
					.Select(g => new
					{
						HotelId = g.Key.HotelId,
						RoomId = g.Key.RoomId,
						Type = g.Key.Type,
						Availability = g.Select(j => j.i).ToArray()
					})
					.ToArray();
					var hparts = CSVSplit(h.HotelInfo).ToArray();
					return new
					{
						HotelId = int.Parse(hparts[0]),
						Destination = hparts[1],
						Phone = hparts[2],
						Description = hparts[3],
						Address = hparts[4],
						Rooms = rooms
					};
				}, new GridSettings() { 
					EnableLocalProcessing = enableLocalProcessing
				})
				.Last();

			var s = new MemoryStream();
			GridUtils.SerializeCustom(s, res);
			s.Seek(0, SeekOrigin.Begin);
			return UTF8Encoding.UTF8.GetString(s.ToArray());
		}

	}
}
